home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / sh-utils.12 / sh-utils / sh-utils-1.12 / src / date.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  9.4 KB  |  389 lines

  1. /* date - print or set the system date and time
  2.    Copyright (C) 89, 90, 91, 92, 93, 1994 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18.    David MacKenzie <djm@gnu.ai.mit.edu> */
  19.  
  20. #include <config.h>
  21. #include <stdio.h>
  22. #include <getopt.h>
  23. #include <sys/types.h>
  24.  
  25. #include "version.h"
  26. #include "system.h"
  27. #include "getline.h"
  28.  
  29. #ifdef TM_IN_SYS_TIME
  30. #include <sys/time.h>
  31. #else
  32. #include <time.h>
  33. #endif
  34.  
  35. #ifndef STDC_HEADERS
  36. size_t strftime ();
  37. time_t time ();
  38. #endif
  39.  
  40. int stime ();
  41.  
  42. char *xrealloc ();
  43. time_t get_date ();
  44. time_t posixtime ();
  45. void error ();
  46.  
  47. static void show_date ();
  48. static void usage ();
  49.  
  50. /* The name this program was run with, for error messages. */
  51. char *program_name;
  52.  
  53. /* If non-zero, display usage information and exit.  */
  54. static int show_help;
  55.  
  56. /* If non-zero, print the version on standard output and exit.  */
  57. static int show_version;
  58.  
  59. /* If non-zero, print or set Coordinated Universal Time.  */
  60. static int universal_time = 0;
  61.  
  62. static struct option const long_options[] =
  63. {
  64.   {"date", required_argument, NULL, 'd'},
  65.   {"file", required_argument, NULL, 'f'},
  66.   {"help", no_argument, &show_help, 1},
  67.   {"set", required_argument, NULL, 's'},
  68.   {"uct", no_argument, NULL, 'u'},
  69.   {"utc", no_argument, NULL, 'u'},
  70.   {"universal", no_argument, NULL, 'u'},
  71.   {"version", no_argument, &show_version, 1},
  72.   {NULL, 0, NULL, 0}
  73. };
  74.  
  75. /* Parse each line in INPUT_FILENAME as with --date and display the
  76.    each resulting time and date.  If the file cannot be opened, tell why
  77.    then exit.  Issue a diagnostic for any lines that cannot be parsed.
  78.    If any line cannot be parsed, return non-zero;  otherwise return zero.  */
  79.  
  80. static int
  81. batch_convert (input_filename, format)
  82.      const char *input_filename;
  83.      const char *format;
  84. {
  85.   int have_read_stdin;
  86.   int status;
  87.   FILE *in_stream;
  88.   char *line;
  89.   int line_length;
  90.   int buflen;
  91.   time_t when;
  92.  
  93.   if (strcmp (input_filename, "-") == 0)
  94.     {
  95.       input_filename = "standard input";
  96.       in_stream = stdin;
  97.       have_read_stdin = 1;
  98.     }
  99.   else
  100.     {
  101.       in_stream = fopen (input_filename, "r");
  102.       if (in_stream == NULL)
  103.     {
  104.       error (0, errno, "%s", input_filename);
  105.     }
  106.       have_read_stdin = 0;
  107.     }
  108.  
  109.   line = NULL;
  110.   buflen = 0;
  111.  
  112.   status = 0;
  113.   while (1)
  114.     {
  115.       line_length = getline (&line, &buflen, in_stream);
  116.       if (line_length < 0)
  117.     {
  118.       /* FIXME: detect/handle error here.  */
  119.       break;
  120.     }
  121.       when = get_date (line, NULL);
  122.       if (when == -1)
  123.     {
  124.       error (0, 0, "invalid date `%s'", line);
  125.       status = 1;
  126.     }
  127.       else
  128.     {
  129.       show_date (format, when);
  130.     }
  131.     }
  132.  
  133.   if (have_read_stdin && fclose (stdin) == EOF)
  134.     error (2, errno, "standard input");
  135.  
  136.   if (line != NULL)
  137.     free (line);
  138.  
  139.   return status;
  140. }
  141.  
  142. void
  143. main (argc, argv)
  144.      int argc;
  145.      char **argv;
  146. {
  147.   int optc;
  148.   const char *datestr = NULL;
  149.   time_t when;
  150.   int set_date = 0;
  151.   int print_date = 0;
  152.   char *format;
  153.   char *batch_file = NULL;
  154.   int n_args;
  155.   int status;
  156.  
  157.   program_name = argv[0];
  158.  
  159.   while ((optc = getopt_long (argc, argv, "d:f:s:u", long_options, (int *) 0))
  160.      != EOF)
  161.     switch (optc)
  162.       {
  163.       case 0:
  164.     break;
  165.       case 'd':
  166.     datestr = optarg;
  167.     print_date = 1;
  168.     break;
  169.       case 'f':
  170.     batch_file = optarg;
  171.     break;
  172.       case 's':
  173.     datestr = optarg;
  174.     set_date = 1;
  175.     break;
  176.       case 'u':
  177.     universal_time = 1;
  178.     break;
  179.       default:
  180.     usage (1);
  181.       }
  182.  
  183.   if (show_version)
  184.     {
  185.       printf ("date - %s\n", version_string);
  186.       exit (0);
  187.     }
  188.  
  189.   if (show_help)
  190.     usage (0);
  191.  
  192.   n_args = argc - optind;
  193.  
  194.   if (set_date && print_date)
  195.     {
  196.       error (0, 0,
  197.       "the options to print and set the time may not be used together");
  198.       usage (1);
  199.     }
  200.  
  201.   if (n_args > 1)
  202.     {
  203.       error (0, 0, "too many non-option arguments");
  204.       usage (1);
  205.     }
  206.  
  207.   if ((set_date || print_date || batch_file != NULL)
  208.       && n_args == 1 && argv[optind][0] != '+')
  209.     {
  210.       error (0, 0, "\
  211. when using the print, set time, or batch options, any\n\
  212. non-option argument must be a format string beginning with `+'");
  213.       usage (1);
  214.     }
  215.  
  216.   if (batch_file != NULL)
  217.     {
  218.       if (set_date || print_date)
  219.     {
  220.       error (0, 0, "\
  221. neither print nor set options may be used when reading dates from a file");
  222.       usage (1);
  223.     }
  224.       status = batch_convert (batch_file,
  225.                   (n_args == 1 ? argv[optind] + 1 : NULL));
  226.     }
  227.   else
  228.     {
  229.       status = 0;
  230.  
  231.       if (!print_date && !set_date)
  232.     {
  233.       if (n_args == 1 && argv[optind][0] != '+')
  234.         {
  235.           /* Prepare to set system clock to the specified date/time
  236.          given in the POSIX-format.  */
  237.           set_date = 1;
  238.           datestr = argv[optind];
  239.           when = posixtime (datestr);
  240.           format = NULL;
  241.         }
  242.       else
  243.         {
  244.           /* Prepare to print the current date/time.  */
  245.           print_date = 1;
  246.           datestr = "undefined";
  247.           time (&when);
  248.           format = (n_args == 1 ? argv[optind] + 1 : NULL);
  249.         }
  250.     }
  251.       else
  252.     {
  253.       /* (print_date || set_date) */
  254.       when = get_date (datestr, NULL);
  255.       format = (n_args == 1 ? argv[optind] + 1 : NULL);
  256.     }
  257.  
  258.       if (when == -1)
  259.     error (1, 0, "invalid date `%s'", datestr);
  260.  
  261.       if (set_date)
  262.     {
  263.       /* Set the system clock to the specified date, then regardless of
  264.          the success of that operation, format and print that date.  */
  265.       if (stime (&when) == -1)
  266.         error (0, errno, "cannot set date");
  267.     }
  268.  
  269.       show_date (format, when);
  270.     }
  271.  
  272.   if (fclose (stdout) == EOF)
  273.     error (2, errno, "write error");
  274.  
  275.   exit (status);
  276. }
  277.  
  278. /* Display the date and/or time in WHEN according to the format specified
  279.    in FORMAT, followed by a newline.  If FORMAT is NULL, use the
  280.    standard output format (ctime style but with a timezone inserted). */
  281.  
  282. static void
  283. show_date (format, when)
  284.      const char *format;
  285.      time_t when;
  286. {
  287.   struct tm *tm;
  288.   char *out = NULL;
  289.   size_t out_length = 0;
  290.  
  291.   tm = (universal_time ? gmtime : localtime) (&when);
  292.  
  293.   if (format == NULL)
  294.     {
  295.       /* Print the date in the default format.  Vanilla ANSI C strftime
  296.          doesn't support %e, but POSIX requires it.  If you don't use
  297.          a GNU strftime, make sure yours supports %e.  */
  298.       format = (universal_time
  299.         ? "%a %b %e %H:%M:%S UTC %Y"
  300.         : "%a %b %e %H:%M:%S %Z %Y");
  301.     }
  302.   else if (*format == '\0')
  303.     {
  304.       printf ("\n");
  305.       return;
  306.     }
  307.  
  308.   do
  309.     {
  310.       out_length += 200;
  311.       out = (char *) xrealloc (out, out_length);
  312.     }
  313.   while (strftime (out, out_length, format, tm) == 0);
  314.  
  315.   printf ("%s\n", out);
  316.   free (out);
  317. }
  318.  
  319. static void
  320. usage (status)
  321.      int status;
  322. {
  323.   if (status != 0)
  324.     fprintf (stderr, "Try `%s --help' for more information.\n",
  325.          program_name);
  326.   else
  327.     {
  328.       printf ("\
  329. Usage: %s [OPTION]... [+FORMAT]\n\
  330.   or:  %s [OPTION] [MMDDhhmm[[CC]YY][.ss]]\n\
  331. ",
  332.           program_name, program_name);
  333.       printf ("\
  334. \n\
  335.   -d, --date=STRING        display time described by STRING, not `now'\n\
  336.   -f, --file=DATEFILE      like --date once for each line of DATEFILE\n\
  337.   -s, --set=STRING         set time described by STRING\n\
  338.   -u, --utc, --universal   print or set Coordinated Universal Time\n\
  339.       --help               display this help and exit\n\
  340.       --version            output version information and exit\n\
  341. ");
  342.       printf ("\
  343. \n\
  344. FORMAT controls the output.  The only valid option for the second form\n\
  345. specifies Coordinated Universal Time.  Interpreted sequences are:\n\
  346. \n\
  347.   %%%%   a literal %%\n\
  348.   %%a   locale's abbreviated weekday name (Sun..Sat)\n\
  349.   %%A   locale's full weekday name, variable length (Sunday..Saturday)\n\
  350.   %%b   locale's abbreviated month name (Jan..Dec)\n\
  351.   %%B   locale's full month name, variable length (January..December)\n\
  352.   %%c   locale's date and time (Sat Nov 04 12:02:33 EST 1989)\n\
  353.   %%d   day of month (01..31)\n\
  354.   %%D   date (mm/dd/yy)\n\
  355.   %%h   same as %%b\n\
  356.   %%H   hour (00..23)\n\
  357.   %%I   hour (01..12)\n\
  358.   %%j   day of year (001..366)\n\
  359.   %%k   hour ( 0..23)\n\
  360.   %%l   hour ( 1..12)\n\
  361.   %%m   month (01..12)\n\
  362.   %%M   minute (00..59)\n\
  363.   %%n   a newline\n\
  364.   %%p   locale's AM or PM\n\
  365.   %%r   time, 12-hour (hh:mm:ss [AP]M)\n\
  366.   %%s   seconds since 00:00:00, Jan 1, 1970 (a GNU extension)\n\
  367.   %%S   second (00..61)\n\
  368.   %%t   a horizontal tab\n\
  369.   %%T   time, 24-hour (hh:mm:ss)\n\
  370.   %%U   week number of year with Sunday as first day of week (00..53)\n\
  371.   %%w   day of week (0..6);  0 represents Sunday\n\
  372.   %%W   week number of year with Monday as first day of week (00..53)\n\
  373.   %%x   locale's date representation (mm/dd/yy)\n\
  374.   %%X   locale's time representation (%%H:%%M:%%S)\n\
  375.   %%y   last two digits of year (00..99)\n\
  376.   %%Y   year (1970...)\n\
  377.   %%Z   time zone (e.g., EDT), or nothing if no time zone is determinable\n\
  378. \n\
  379. By default, `date' pads numeric fields with zeroes.  GNU `date'\n\
  380. recognizes the following nonstandard modifiers between `%%' and a\n\
  381. numeric directive.\n\
  382. \n\
  383.   `-' (hyphen) do not pad the field\n\
  384.   `_' (underscore) pad the field with spaces\n\
  385. ");
  386.     }
  387.   exit (status);
  388. }
  389.